﻿using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace System.Windows
{
    public static partial class UIElementExtension
    {
        public static Rect InvisibleBounds = new Rect(-1000000, 0, 0, 0);

        public static bool GetVisible(this UIElement element)
        {
            return element.Visibility == Visibility.Visible;
        }

        public static void SetVisible(this UIElement element, bool visible)
        {
            Visibility newVisibiliity = visible ? Visibility.Visible : Visibility.Collapsed;
            if (newVisibiliity != element.Visibility)
            {
                element.Visibility = newVisibiliity;
                //INotifyVisibilityChanged notifyVisibilityChanged = element as INotifyVisibilityChanged;
                //if (notifyVisibilityChanged != null)
                //    notifyVisibilityChanged.OnVisibilityChanged();
            }
        }

        public static Size GetDesiredSize(this UIElement element)
        {
            return element.DesiredSize;
        }

        public static double GetRoundedSize(double size)
        {
            return Math.Ceiling(size);
        }

        public static Size GetRoundedSize(Size size)
        {
            return new Size(Math.Ceiling(size.Width), Math.Ceiling(size.Height));
        }

        public static FrameworkElement GetRootVisual(this UIElement element)
        {
            if (!BrowserInteropHelper.IsBrowserHosted)
            {
                PresentationSource presentationSource = PresentationSource.FromVisual(element);
                return presentationSource != null ? presentationSource.RootVisual as FrameworkElement : null;
            }
            else
                return (FrameworkElement)Application.Current.MainWindow.Content;
        }

        public static Point MapPoint(this UIElement element, Point p, UIElement destination)
        {
            if (destination != null)
                return element.TranslatePoint(p, destination);
            else
                if (!BrowserInteropHelper.IsBrowserHosted)
                    return element.PointToScreen(p);
                else
                    return element.TranslatePoint(p, element.GetRootVisual());
        }

        public static Point MapPointFromScreen(this UIElement element, Point p)
        {
            if (!BrowserInteropHelper.IsBrowserHosted)
                return element.PointFromScreen(p);
            else
                return element.GetRootVisual().MapPoint(p, element);
        }

        public static Rect MapRect(this UIElement element, Rect rect, UIElement destination)
        {
            return new Rect(element.MapPoint(rect.TopLeft(), destination), element.MapPoint(rect.BottomRight(), destination));
        }

        public static Rect MapRectFromScreen(this UIElement element, Rect rect)
        {
            return new Rect(element.MapPointFromScreen(rect.TopLeft()), element.MapPointFromScreen(rect.BottomRight()));
        }

        public static bool HasDefaultRenderTransform(this UIElement element)
        {
            return element.RenderTransform == null ||
                element.RenderTransform is MatrixTransform && ((MatrixTransform)element.RenderTransform).Matrix.IsIdentity;
        }

        public static bool Focus(this UIElement element)
        {
            if (element is Control)
                return (element as Control).Focus();
            return false;
        }

        public static void InvalidateParentsOfModifiedChildren(this UIElement element)
        {
            bool needsRemeasuring = false;
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
            {
                var child = VisualTreeHelper.GetChild(element, i) as UIElement;
                if (child != null)
                {
                    InvalidateParentsOfModifiedChildren(child);
                    if (!child.IsMeasureValid)
                        needsRemeasuring = true;
                }
            }
            if (needsRemeasuring)
                element.InvalidateMeasure();
        }

        /// <summary>
        ///   Renders the ui element into a bitmap frame.
        /// </summary>
        /// <param name = "element">The UI element.</param>
        /// <returns>The created bitmap frame</returns>
        public static BitmapSource RenderToBitmap(this UIElement element)
        {
            return element.RenderToBitmap(1);
        }

        /// <summary>
        ///   Renders the ui element into a bitmap frame using the specified scale.
        /// </summary>
        /// <param name = "element">The UI element.</param>
        /// <param name = "scale">The scale (default: 1).</param>
        /// <returns>The created bitmap frame</returns>
        public static BitmapSource RenderToBitmap(this UIElement element, double scale)
        {
            var renderWidth = (int)(element.RenderSize.Width * scale);
            var renderHeight = (int)(element.RenderSize.Height * scale);

            var renderTarget = new RenderTargetBitmap(renderWidth, renderHeight, 96, 96, PixelFormats.Pbgra32);
            var sourceBrush = new VisualBrush(element);

            var drawingVisual = new DrawingVisual();
            var drawingContext = drawingVisual.RenderOpen();

            using (drawingContext)
            {
                drawingContext.PushTransform(new ScaleTransform(scale, scale));
                drawingContext.DrawRectangle(sourceBrush, null, new Rect(new Point(0, 0), new Point(element.RenderSize.Width, element.RenderSize.Height)));
            }
            renderTarget.Render(drawingVisual);

            return renderTarget;
        }

        /// <summary>
        /// Brings  the control in the control collection to top
        /// </summary>
        /// <param name="collection">UI Collection</param>
        /// <param name="control">Element to be brought to front</param>
        public static void SendToFront(this UIElementCollection collection, UIElement control)
        {
            collection.Remove(control);
            collection.Add(control);
        }
    }
}